package com.ken.astroboy.web;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.quartz.CronExpression;
import org.quartz.Job;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.ken.astroboy.core.Constant;
import com.ken.astroboy.core.InMemoryStorage;
import com.ken.astroboy.dto.AutoReplyDto;
import com.ken.astroboy.dto.MsgToSendDto;
import com.ken.astroboy.dto.ScheduledTaskDto;
import com.ken.astroboy.dto.WelcomeMsgDto;
import com.ken.astroboy.logic.LogicProcess;
import com.ken.astroboy.model.AutoReplyItem;
import com.ken.astroboy.model.ScheduledTaskCustomData;
import com.ken.astroboy.model.ScheduledTaskItem;
import com.ken.astroboy.model.WelcomeMsgItem;
import com.ken.astroboy.result.OperationResult;
import com.ken.astroboy.service.WxService;
import com.ken.astroboy.thread.InitRobotThread;
import com.ken.astroboy.util.Exceptions;
import com.ken.astroboy.util.GetExecuteTimeForCronExpression;
import com.ken.astroboy.util.SimpleCipher;
import com.ken.astroboy.vo.AutoReplyVo;
import com.ken.astroboy.vo.FriendVo;
import com.ken.astroboy.vo.GroupVo;
import com.ken.astroboy.vo.MemberVo;
import com.ken.astroboy.vo.RobotInfo;
import com.ken.astroboy.vo.ScheduledTaskVo;
import com.ken.astroboy.vo.WelcomeMsgVo;

@Controller
@RequestMapping("/robot")
public class RobotController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @RequestMapping("onboard")
    @ResponseBody
    public Object login(HttpServletRequest request) throws IOException {

        logger.debug("Enter /robot/onboard");

        //referer: http://localhost:8080/admin/home
        //直接输入http://localhost:8080/robot/login时，referer为null
        //todo: 以后通过判断referer来阻止直接输入robot/login
        logger.debug("referer: {}", request.getHeader("referer"));

        Map<String, String> map = new HashMap<>();

        if(InMemoryStorage.isRobotInitializing){
            logger.debug("ROBOT_IS_INITIALIZING");
            map.put("status", "ROBOT_IS_INITIALIZING");
        }else if(InMemoryStorage.isRobotOnline){
            logger.debug("ROBOT_LOGIN_SUCCESS");
            map.put("status", "ROBOT_LOGIN_SUCCESS");
        }else{

            logger.debug("ROBOT_LOGIN_START...");

            LogicProcess.initDataInWxServiceAndInMemoryStorage();
            LogicProcess.loadCustomConfig();

            //request.getSession().getServletContext().getRealPath("") 返回的是webapp目录所在的全路径
            
            String randomString = String.valueOf(System.currentTimeMillis());
            
            String qrCodefileRealPath = request.getSession().getServletContext().getRealPath("") + "/" + randomString + Constant.QrCodeFile;
            
            logger.info("qrCodefileRealPath: {}", qrCodefileRealPath);

            StringBuilder sb = new StringBuilder();
            sb.append(request.getScheme())
            .append("://")
            .append(request.getServerName())
            .append(":")
            .append(request.getServerPort())
            .append(request.getContextPath())
            .append("/")
            .append(randomString)
            .append(Constant.QrCodeFile);

            logger.info("qrCodeFileAccessUrl: {}", sb.toString());

            if(LogicProcess.getQrCodeFilePath(qrCodefileRealPath)){
                map.put("status", "GET_QR_CODE_FILE_SUCCESS");
                map.put("qrCodeFileAccessUrl", sb.toString());
            }else{
                map.put("status", "GET_QR_CODE_FILE_FAIL");                
            }

            InMemoryStorage.isRobotInitializing = true;
           
            InitRobotThread initRobotThread = new InitRobotThread();
            new Thread(initRobotThread).start();   

        }

        return map;                  
    }


    @RequestMapping("quit")
    @ResponseBody
    public Object quit(HttpServletRequest request){
        
    	logger.info("进入机器人下线处理");
    	
        if(!LogicProcess.removeAllJobs()){
            logger.info("删除全部定时任务失败");
            
            //todo:是否需要重启服务器？
        }
        
        InMemoryStorage.keepListening = false;        
        InMemoryStorage.isRobotOnline = false;
        InMemoryStorage.isRobotHealthy = false;
        LogicProcess.initDataInWxServiceAndInMemoryStorage();
        
        //睡眠3秒钟，等待WechatListener完全退出
        try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

        return new OperationResult(true, "ok");

    }
    
    
    @RequestMapping("panel")
    public String panel() {

        if(InMemoryStorage.isRobotOnline){
            return "panel";            
        }else{
            return "redirect:/home";
        }
    }

    @RequestMapping("info")
    @ResponseBody
    public Object info() {

        RobotInfo robot = new RobotInfo();
               
        robot.setHealthy(InMemoryStorage.isRobotHealthy);
        robot.setInitializing(InMemoryStorage.isRobotInitializing);
        robot.setOnline(InMemoryStorage.isRobotOnline);
               
        if(InMemoryStorage.isRobotOnline){           
            robot.setNickName(WxService.getUser().getNickName());
            robot.setAvatar(WxService.getAvatarUrl());
        }
        
        return robot;       
    }
    

    @RequestMapping("group-list")
    @ResponseBody
    public Object groupList(@RequestParam(value = "type", required = false) String type) {

        boolean requireFullList = true;
        
        if(StringUtils.isNotBlank(type)){
            if("registered".equals(type)){
                requireFullList = false;
            }
        }
        
        List<GroupVo> list = LogicProcess.getGroupList(requireFullList);

        return list;        
    } 

    @RequestMapping("friend-list")
    @ResponseBody    
    public Object friendList() {

        List<FriendVo> list = LogicProcess.getFriendList();

        return list;        
    } 

    @RequestMapping("getMember/{group}")
    @ResponseBody
    public Object getMember(@PathVariable String group) {

        List<MemberVo> list = LogicProcess.getMemberList(SimpleCipher.decrypt(group));

        return list; 
    }

    @RequestMapping("addCtrl/{group}")
    @ResponseBody
    public Object addCtrl(@PathVariable String group) {

        logger.debug("Enter /robot/addCtrl/{group}");
        logger.debug("group: {}", group);


        if(LogicProcess.addGroupToUnderCtrlList(SimpleCipher.decrypt(group))){

            return LogicProcess.getGroupList(true);

        }else{                       
            return new OperationResult(false, "fail");
        }

    }

    @RequestMapping("removeCtrl/{group}")
    @ResponseBody
    public Object removeCtrl(@PathVariable String group) {

        logger.debug("Enter /robot/removeCtrl/{group}");
        logger.debug("group: {}", group);

        if(LogicProcess.removeGroupFromUnderCtrlList(SimpleCipher.decrypt(group))){

            return LogicProcess.getGroupList(true);

        }else{                       
            return new OperationResult(false, "fail");
        }
    } 

    @RequestMapping("enSignIn/{group}")
    @ResponseBody
    public Object enSignIn(@PathVariable String group) {

        logger.debug("Enter /robot/enSignIn/{group}");
        logger.debug("group: {}", group);

        if(LogicProcess.addGroupToSignInList(SimpleCipher.decrypt(group))){

            return LogicProcess.getGroupList(true);

        }else{                       
            return new OperationResult(false, "fail");
        }
    }

    @RequestMapping("disSignIn/{group}")
    @ResponseBody
    public Object disSignIn(@PathVariable String group) {

        logger.debug("Enter /robot/disSignIn/{group}");
        logger.debug("group: {}", group);

        if(LogicProcess.removeGroupFromSignInList(SimpleCipher.decrypt(group))){

            return LogicProcess.getGroupList(true);

        }else{                       
            return new OperationResult(false, "fail");
        }
    } 

    @RequestMapping("updateGroup/{group}")
    @ResponseBody
    public Object updateGroup(@PathVariable String group) {

        logger.debug("Enter /robot/updateGroup/{group}");
        logger.debug("group: {}", group);

        LogicProcess.updateGroupData(SimpleCipher.decrypt(group));

        return LogicProcess.getGroupList(true);
    }

    @RequestMapping("sendWelcomeMsg/{group}")
    @ResponseBody
    public Object sendWelcomeMsg(@PathVariable String group) {

        logger.debug("Enter /robot/sendWelcomeMsg/{group}");
        logger.debug("group: {}", group);
        
        OperationResult result = new OperationResult();

        String groupNickName = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(group));

        WelcomeMsgItem welcomeMsgItem = LogicProcess.findWelcomeMsgItem(groupNickName);

        if(welcomeMsgItem != null){
            if(welcomeMsgItem.getMsgStatus() == WelcomeMsgItem.ENABLED){
                LogicProcess.sendWelcomeMsg(groupNickName, InMemoryStorage.newMemberMap.get(groupNickName));

                if(InMemoryStorage.newMemberMap.get(groupNickName) != null){
                    InMemoryStorage.newMemberMap.get(groupNickName).clear();
                }

                result.setStatus(true);
                result.setDescription("欢迎消息发到[" + groupNickName + "]啦");
                
            }else{
                result.setStatus(false);
                result.setDescription("[" + groupNickName + "] 的欢迎消息已停用");
          }                 
        }else{
            result.setStatus(false);
            result.setDescription("[" + groupNickName + "] 木有配置欢迎消息喔");
        }                       
        
        return result;
    }
    
    @RequestMapping("signIn")
    @ResponseBody
    public Object signIn(String group, String member) {

        logger.debug("Enter /robot/signIn");
        logger.debug("group: {}", group);
        logger.debug("member: {}", member);

        String groupUserName = InMemoryStorage.findGroupUserName(group);

        try {
            LogicProcess.processSignIn(groupUserName, group, member, -1);

            return LogicProcess.getMemberList(groupUserName);
        } catch (IOException e) {
            logger.info(Exceptions.getExceptionDetail(e));

            return new OperationResult(false, "fail");
        }           

    }

    @RequestMapping(value="sendMsg", method=RequestMethod.POST)
    @ResponseBody
    public OperationResult sendMsg(MsgToSendDto msg, HttpServletRequest request) {

        logger.debug("Enter /robot/sendMsg");
        logger.debug("MsgToSendDto: {}", msg.toString());

        OperationResult result = new OperationResult(true, "ok");

        if(StringUtils.isBlank(msg.getTextToSend())
                && StringUtils.isBlank(msg.getImgToSend())){
            
            result.setStatus(false);
            result.setDescription("文字和图片都为空");           
            return result;
        }
        
        boolean noTarget = false;
        
        if( msg.getWxGroupSelected() == null ){                       
            if( msg.getCustomGroupSelected() == null ){
                noTarget = true;
            }else{
                if(msg.getCustomGroupSelected().isEmpty()){
                    noTarget = true;
                }
            }
        }else{
            
            if(msg.getWxGroupSelected().isEmpty()){
                if( msg.getCustomGroupSelected() == null ){
                    noTarget = true;
                }else{
                    if(msg.getCustomGroupSelected().isEmpty()){
                        noTarget = true;
                    }
                }
            }
        }
        
        if(noTarget){
            result.setStatus(false);
            result.setDescription("要发送的群和分组都为空");
            return result;           
        }
        
        if(StringUtils.isNotBlank(msg.getTextToSend())){

            for(String group: msg.getWxGroupSelected()){
                WxService.sendTextMsg(msg.getTextToSend(), SimpleCipher.decrypt(group));
            }
        }
        
        if(StringUtils.isNotBlank(msg.getImgToSend())){
            
            String filePath = request.getSession().getServletContext().getRealPath("static/upload/temp/" + msg.getImgToSend());
            
            for(String group: msg.getWxGroupSelected()){
                WxService.sendImgMsg(filePath, SimpleCipher.decrypt(group));
            }
        }

        return result;
    }

    @RequestMapping("auto-reply-list")
    @ResponseBody
    public Object autoReplyList() {

        List<AutoReplyVo> list = LogicProcess.getAutoReplyList();

        return list;        
    } 

    @RequestMapping("welcome-msg-list")
    @ResponseBody
    public Object welcomeMsgList() {

        List<WelcomeMsgVo> list = LogicProcess.getWelcomeMsgList();

        return list;        
    } 

    @RequestMapping("scheduled-task-list")
    @ResponseBody
    public Object scheduledTaskList() {

        List<ScheduledTaskVo> list = LogicProcess.getScheduledTaskList();

        return list;        
    }

    @RequestMapping("upload")
    @ResponseBody
    public Object upload(@RequestParam(value = "fileContent", required = false) MultipartFile fileContent,
                         @RequestParam(value = "expectedFolder", required = false) String expectedFolder, 
                         @RequestParam(value = "expectedFileName", required = false) String expectedFileName, 
                            HttpServletRequest request, ModelMap model) {  

        logger.debug("进人 /robot/upload"); 

        Map<String, String> result = new HashMap<>();
        
        String fileFolder = null;
        String filePath = null;
        String fileName = null;
                
        if(fileContent != null){          
            if(StringUtils.isBlank(expectedFolder)){
                fileFolder = "nopath";
            }else{
                fileFolder = expectedFolder;
            }
            
            filePath = request.getSession().getServletContext().getRealPath("static/upload/" + fileFolder);

            String originalFileName = fileContent.getOriginalFilename();
            String suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
            
            if(StringUtils.isBlank(expectedFileName)){
                //fileName = fileContent.getOriginalFilename();
                //生成永不重复的随机文件名，同时也防止用户上传的文件包含中文名
                fileName = UUID.randomUUID().toString() + "." + suffix;
            }else{
                fileName = expectedFileName + "." + suffix;
            }
            
            logger.debug("filePath: {}", filePath); 
            logger.debug("fileName: {}", fileName); 
            
            File targetFile = new File(filePath, fileName);  
            if(!targetFile.exists()){  
                targetFile.mkdirs();  
            } 
            
            //保存  
            try {  
                fileContent.transferTo(targetFile); 
                                
                StringBuilder sb = new StringBuilder();
                
                sb.append(request.getScheme())
                .append("://")
                .append(request.getServerName())
                .append(":")
                .append(request.getServerPort())
                .append(request.getContextPath())
                .append("/static/upload/")
                .append(fileFolder)
                .append("/")
                .append(fileName);
                
                result.put("status", "true");
                result.put("imgToSend", fileName);
                result.put("selectedImgUrl", sb.toString());
                
            } catch (Exception e) {  
                logger.info(Exceptions.getExceptionDetail(e));
                
                result.put("status", "false");
                result.put("description", "上传文件时出现异常");
            } 
        }else{
            result.put("status", "false");
            result.put("description", "上传文件时MultipartFile为 null");
        }

        return result;
    }

    @RequestMapping("addAdmin/{friend}")
    @ResponseBody
    public Object addAdmin(@PathVariable String friend) {

        logger.debug("Enter /robot/addAdmin/{friend}");
        logger.debug("friend: {}", friend);

        String nickName = InMemoryStorage.findSenderNickName(SimpleCipher.decrypt(friend));

        if(nickName != null){

            try {
                LogicProcess.addFriendToAdminList(nickName);
                return LogicProcess.getFriendList();
            } catch (IOException e) {
                logger.info(Exceptions.getExceptionDetail(e));
            }                   
        }

        return new OperationResult(false, "fail");    
    }

    @RequestMapping("removeAdmin/{friend}")
    @ResponseBody
    public Object removeAdmin(@PathVariable String friend) {

        logger.debug("Enter /robot/removeAdmin/{friend}");
        logger.debug("friend: {}", friend);

        String nickName = InMemoryStorage.findSenderNickName(SimpleCipher.decrypt(friend));

        if(nickName != null){

            try {
                LogicProcess.removeFriendFromAdminList(nickName);
                return LogicProcess.getFriendList();
            } catch (IOException e) {
                logger.info(Exceptions.getExceptionDetail(e));
            }                   
        }

        return new OperationResult(false, "fail");    
    }

    @RequestMapping("enReceiveMsg/{friend}")
    @ResponseBody
    public Object enReceiveMsg(@PathVariable String friend) {

        logger.debug("Enter /robot/enReceiveMsg/{friend}");
        logger.debug("friend: {}", friend);

        String nickName = InMemoryStorage.findSenderNickName(SimpleCipher.decrypt(friend));

        if(nickName != null){

            try {
                LogicProcess.addFriendToNoticeReceiverList(nickName);
                return LogicProcess.getFriendList();
            } catch (IOException e) {
                logger.info(Exceptions.getExceptionDetail(e));
            }                   
        }

        return new OperationResult(false, "fail");    
    }

    @RequestMapping("disReceiveMsg/{friend}")
    @ResponseBody
    public Object disReceiveMsg(@PathVariable String friend) {

        logger.debug("Enter /robot/disReceiveMsg/{friend}");
        logger.debug("friend: {}", friend);

        String nickName = InMemoryStorage.findSenderNickName(SimpleCipher.decrypt(friend));

        if(nickName != null){

            try {
                LogicProcess.removeFriendFromNoticeReceiverList(nickName);
                return LogicProcess.getFriendList();
            } catch (IOException e) {
                logger.info(Exceptions.getExceptionDetail(e));
            }                   
        }

        return new OperationResult(false, "fail");    
    }     
    
    
    //------------------AutoReply-----------------
    
    @RequestMapping("pauseAutoReply")
    @ResponseBody
    public Object pauseAutoReply(String name) {

        logger.debug("Enter /robot/pauseAutoReply");
        logger.debug("name: {}", name);

        if(LogicProcess.pauseAutoReply(name)){

            return LogicProcess.getAutoReplyList();

        }else{                       
            return new OperationResult(false, "fail");
        }
    } 
    
    @RequestMapping("resumeAutoReply")
    @ResponseBody
    public Object resumeAutoReply(String name) {

        logger.debug("Enter /robot/resumeAutoReply");
        logger.debug("name: {}", name);

        if(LogicProcess.resumeAutoReply(name)){

            return LogicProcess.getAutoReplyList();

        }else{                       
            return new OperationResult(false, "fail");
        }
    }

    @RequestMapping("removeAutoReply")
    @ResponseBody
    public Object removeAutoReply(String name) {

        logger.debug("Enter /robot/removeAutoReply");
        logger.debug("name: {}", name);

        if(LogicProcess.removeAutoReply(name)){

            return LogicProcess.getAutoReplyList();

        }else{                       
            return new OperationResult(false, "fail");
        }
    }

    @RequestMapping(value="autoReply", method=RequestMethod.POST)
    @ResponseBody
    public Object autoReply(AutoReplyDto msg, HttpServletRequest request) {

        logger.debug("Enter /robot/autoReply");
        logger.debug("AutoReplyDto: {}", msg.toString());

        OperationResult result = new OperationResult(true, "ok");

        StringBuilder errorReport = new StringBuilder();
        String keyword = StringUtils.trim(msg.getKeyword());
        boolean isCreate = false;

        if(AutoReplyDto.CREATE_MODE.equals(msg.getMode())){
            
            isCreate = true;
            
            //Check keyword
            if(StringUtils.isBlank(keyword)){
                errorReport.append("关键词为空\r\n");
            }else if(keyword.contains("打卡") ||
                    keyword.startsWith("问题：") || keyword.startsWith("问题:") ||
                    keyword.startsWith("提问：") || keyword.startsWith("提问:") ){
                errorReport.append("关键词[" + keyword + "]包含系统保留关键词（打卡、问题:、提问:）\r\n");
            }else if(InMemoryStorage.autoReplyEntity.getMap().containsKey(keyword)){
                errorReport.append("关键词[" + keyword + "]已存在\r\n");
            }
        }


        //Check group 
        boolean noTarget = false;
        boolean groupSelected = false;

        if( msg.getWxGroupSelected() == null ){                       
            if( msg.getCustomGroupSelected() == null ){
                noTarget = true;
            }else{
                if(msg.getCustomGroupSelected().isEmpty()){
                    noTarget = true;
                }
            }
        }else{

            if(msg.getWxGroupSelected().isEmpty()){
                if( msg.getCustomGroupSelected() == null ){
                    noTarget = true;
                }else{
                    if(msg.getCustomGroupSelected().isEmpty()){
                        noTarget = true;
                    }
                }
            }else{
                groupSelected = true;
            }
        }

        if(noTarget){
            errorReport.append("微信群和分组都为空\r\n");          
        }else{
            if(groupSelected){
                for(String item : msg.getWxGroupSelected()){
                    String group = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(item));
                    if(!InMemoryStorage.userGroupCtrlEntity.getGroupList().contains(StringUtils.trim(group))){
                        errorReport.append("微信群[" + group + "]尚未被收编群\r\n");
                    }
                }                
            }
        }

        //Check msg
        if(StringUtils.isBlank(StringUtils.trim(msg.getTextToSend1())) 
                && StringUtils.isBlank(StringUtils.trim(msg.getTextToSend2()))
                && StringUtils.isBlank(StringUtils.trim(msg.getImgToSend())) ){
            errorReport.append("发送消息和图片都为空\r\n");                       
        }
        
        if(errorReport.length() == 0){

            AutoReplyItem item = new AutoReplyItem();
            
            item.setStatus(AutoReplyItem.ENABLED);
            
            if(AutoReplyDto.EDIT_MODE.equals(msg.getMode())){
                
                AutoReplyItem old = InMemoryStorage.autoReplyEntity.getMap().get(keyword);
                
                if(old != null){
                    item.setStatus(old.getStatus());
                }           
            }                    

            
            if( msg.getWxGroupSelected() != null ){
                if(!msg.getWxGroupSelected().isEmpty()){
                    for(String userName : msg.getWxGroupSelected()){
                        String group = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(userName));
                        if(StringUtils.isNotBlank(group)){
                            item.getGroupList().add(group);
                        }
                    }                     
                }
            }

            if(StringUtils.isNotBlank(msg.getIgnoredSender())){
                String[] users = StringUtils.trim(msg.getIgnoredSender()).split(";");
                if(users != null){
                    for(String user : users){
                        if(StringUtils.isNotBlank(user)){
                            item.getExcludedUserList().add(user);
                        }
                    }                               
                }                       
            }


            item.getTextList().add(msg.getTextToSend1());
            item.getTextList().add(msg.getTextToSend2());

            if(StringUtils.isNotBlank(msg.getImgToSend())){
                item.getImageList().clear();
                item.getImageList().add(request.getSession().getServletContext().getRealPath("") + "/static/upload/autoReply/" + msg.getImgToSend());
            }

            if(LogicProcess.createOrModifyAutoReply(keyword, item, isCreate)){
                List<AutoReplyVo> list = LogicProcess.getAutoReplyList();
                return list; 
            }else{
                result.setStatus(false);
                result.setDescription("保存失败");  
            }
        }else{    
            result.setStatus(false);
            result.setDescription("输入参数有误：" + errorReport);
        }

        return result;              
    }

    @RequestMapping("getAutoReply")
    @ResponseBody
    public Object getAutoReply(String name, HttpServletRequest request) {

        logger.debug("Enter /robot/getAutoReply");
        logger.debug("name: {}", name);

        AutoReplyItem item =
                InMemoryStorage.autoReplyEntity.getMap().get(name);
        
        AutoReplyDto dto = new AutoReplyDto();
        
        dto.setKeyword(name);
        
        List<String> textList = item.getTextList();
        if(textList != null){
            if(textList.size() == 1){
                dto.setTextToSend1(textList.get(0));
            }else if(textList.size() >= 2){
                dto.setTextToSend1(textList.get(0));
                dto.setTextToSend2(textList.get(1));
            }          
        }
        
        List<String> imageList = item.getImageList();
        if(imageList != null){
            if(imageList.size() > 0){
                String image = item.getImageList().get(0);
                
                if(StringUtils.isNotBlank(image)){
                    
                    String fileName = image.substring(image.lastIndexOf("/") + 1);
                    
                    dto.setImgToSend(fileName);                    

                    StringBuilder sb = new StringBuilder();
                    
                    sb.append(request.getScheme())
                    .append("://")
                    .append(request.getServerName())
                    .append(":")
                    .append(request.getServerPort())
                    .append(request.getContextPath())
                    .append("/static/upload/autoReply/")
                    .append(fileName);
                    
                    dto.setSelectedImgUrl(sb.toString());
                }
            }
        }
        
        
        for(String group : item.getGroupList()){
            String userName = InMemoryStorage.findGroupUserName(group);
            if(userName != null){
                dto.getWxGroupSelected().add(SimpleCipher.encrypt(userName));
            }
        }
        
        StringBuilder sb = new StringBuilder();
        for(String user : item.getExcludedUserList()){
            sb.append(user).append(";");
        }
        dto.setIgnoredSender(sb.toString());
        
        dto.setWxGroupAll(LogicProcess.getGroupList(false));

        return dto;
    }    
    
    //------------------WelcomeMsg-----------------
    
    @RequestMapping(value="welcomeMsg", method=RequestMethod.POST)
    @ResponseBody
    public Object welcomeMsg(WelcomeMsgDto msg, HttpServletRequest request) {

        logger.debug("Enter /robot/welcomeMsg");
        logger.debug("WelcomeMsgDto: {}", msg.toString());

        OperationResult result = new OperationResult(true, "ok");

        StringBuilder errorReport = new StringBuilder();
        String msgName = StringUtils.trim(msg.getKeyword());
        boolean isCreate = false;

        if(WelcomeMsgDto.CREATE_MODE.equals(msg.getMode())){
            
            isCreate = true;
            
            //Check keyword
    
            if(StringUtils.isBlank(msgName)){
                errorReport.append("欢迎消息名称为空\r\n");
            }else if(InMemoryStorage.welcomeMsgEntity.getMap().containsKey(msgName)){
                errorReport.append("欢迎消息名称[" + msgName + "]已存在\r\n");
            }              
        }
        
        //Check 入群人数
        if(StringUtils.isBlank(StringUtils.trim(msg.getThreshold()))) {
            errorReport.append("入群人数为空\r\n");
        }else{

            Pattern pattern = Pattern.compile("[1-9]"); 
            Matcher isNum = pattern.matcher(StringUtils.trim(msg.getThreshold()));
            if( !isNum.matches() ){ 
                errorReport.append("入群人数必须为1-9的整数\r\n");
            }               
        }

        
        //Check group
        boolean noTarget = false;
        boolean groupSelected = false;

        if( msg.getWxGroupSelected() == null ){                       
            if( msg.getCustomGroupSelected() == null ){
                noTarget = true;
            }else{
                if(msg.getCustomGroupSelected().isEmpty()){
                    noTarget = true;
                }
            }
        }else{

            if(msg.getWxGroupSelected().isEmpty()){
                if( msg.getCustomGroupSelected() == null ){
                    noTarget = true;
                }else{
                    if(msg.getCustomGroupSelected().isEmpty()){
                        noTarget = true;
                    }
                }
            }else{
                groupSelected = true;
            }
        }

        if(noTarget){
            errorReport.append("微信群和分组都为空\r\n");          
        }else{
            if(groupSelected){
                for(String item : msg.getWxGroupSelected()){
                    String group = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(item));
                    if(InMemoryStorage.userGroupCtrlEntity.getGroupList().contains(StringUtils.trim(group))){
                                           
                        for(Map.Entry<String, WelcomeMsgItem> entry : InMemoryStorage.welcomeMsgEntity.getMap().entrySet()){                            

                            if(WelcomeMsgDto.EDIT_MODE.equals(msg.getMode())){
                                if(msgName.equals(entry.getKey())){
                                    continue;
                                }
                            }
                            
                            if(entry.getValue().getGroupReceivers().contains(group)){
                                errorReport.append("[") 
                                           .append(group)
                                           .append("] 已被配置在欢迎消息 [")
                                           .append(entry.getKey())
                                           .append("] 中，不可重复配置\r\n");
                            }
                        }
                    
                    }else{
                        errorReport.append("微信群[" + group + "]尚未被收编群\r\n");
                    }
                }                
            }
        }

        //Check msg
        if(StringUtils.isBlank(StringUtils.trim(msg.getTextToSend1())) 
                && StringUtils.isBlank(StringUtils.trim(msg.getTextToSend2()))
                && StringUtils.isBlank(StringUtils.trim(msg.getImgToSend())) ){
            errorReport.append("发送消息和图片都为空\r\n");                       
        }                  

        
        if(errorReport.length() == 0){
          
            WelcomeMsgItem item = new WelcomeMsgItem();

            item.setMsgStatus(WelcomeMsgItem.ENABLED);
            
            if(WelcomeMsgDto.EDIT_MODE.equals(msg.getMode())){
                
                WelcomeMsgItem old = InMemoryStorage.welcomeMsgEntity.getMap().get(msgName);
                
                if(old != null){
                    item.setMsgStatus(old.getMsgStatus());
                }           
            } 
            
            if( msg.getWxGroupSelected() != null ){
                if(!msg.getWxGroupSelected().isEmpty()){
                    for(String userName : msg.getWxGroupSelected()){
                        String group = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(userName));
                        if(StringUtils.isNotBlank(group)){
                            item.getGroupReceivers().add(group);
                        }
                    }                     
                }
            }

            item.getTextList().add(msg.getTextToSend1());
            item.getTextList().add(msg.getTextToSend2());

            if(StringUtils.isNotBlank(msg.getImgToSend())){
                item.getImageList().clear();
                item.getImageList().add(request.getSession().getServletContext().getRealPath("") + "/static/upload/welcomeMsg/" + msg.getImgToSend());
            }

            item.setThreshold(Long.valueOf((StringUtils.trim(msg.getThreshold()))));

            if(LogicProcess.createOrModifyWelcomeMsg(msgName, item, isCreate)){
                List<WelcomeMsgVo> list = LogicProcess.getWelcomeMsgList();
                return list; 
            }else{
                result.setStatus(false);
                result.setDescription("保存失败");  
            }
        }else{    
            result.setStatus(false);
            result.setDescription("输入参数有误：" + errorReport);
        }

        return result;              
    }

    @RequestMapping("disWelcomeMsg")
    @ResponseBody
    public Object disWelcomeMsg(String name) {

        logger.debug("Enter /robot/disWelcomeMsg");
        logger.debug("name: {}", name);

        if(LogicProcess.pauseWelcomeMsg(name)){
            List<WelcomeMsgVo> list = LogicProcess.getWelcomeMsgList();

            return list;
        }else{
            return new OperationResult(false, "fail");
        }
    }
    
    @RequestMapping("enWelcomeMsg")
    @ResponseBody
    public Object enWelcomeMsg(String name) {

        logger.debug("Enter /robot/enWelcomeMsg");
        logger.debug("name: {}", name);

        if(LogicProcess.resumeWelcomeMsg(name)){
            List<WelcomeMsgVo> list = LogicProcess.getWelcomeMsgList();

            return list;
        }else{
            return new OperationResult(false, "fail");
        }
    }

    @RequestMapping("removeWelcomeMsg")
    @ResponseBody
    public Object removeWelcomeMsg(String name) {

        logger.debug("Enter /robot/removeWelcomeMsg");
        logger.debug("name: {}", name);

        if(LogicProcess.removeWelcomeMsg(name)){
            List<WelcomeMsgVo> list = LogicProcess.getWelcomeMsgList();

            return list;
        }else{
            return new OperationResult(false, "fail");
        }
    }
    
    @RequestMapping("getWelcomeMsg")
    @ResponseBody
    public Object getWelcomeMsg(String name, HttpServletRequest request) {

        logger.debug("Enter /robot/getWelcomeMsg");
        logger.debug("name: {}", name);

        WelcomeMsgItem item =
                InMemoryStorage.welcomeMsgEntity.getMap().get(name);
        
        WelcomeMsgDto dto = new WelcomeMsgDto();
        
        dto.setKeyword(name);
        
        List<String> textList = item.getTextList();
        if(textList != null){
            if(textList.size() == 1){
                dto.setTextToSend1(textList.get(0));
            }else if(textList.size() >= 2){
                dto.setTextToSend1(textList.get(0));
                dto.setTextToSend2(textList.get(1));
            }          
        }
        
        List<String> imageList = item.getImageList();
        if(imageList != null){
            if(imageList.size() > 0){
                String image = item.getImageList().get(0);
                
                if(StringUtils.isNotBlank(image)){
                    
                    String fileName = image.substring(image.lastIndexOf("/") + 1);
                    
                    dto.setImgToSend(fileName);                    

                    StringBuilder sb = new StringBuilder();
                    
                    sb.append(request.getScheme())
                    .append("://")
                    .append(request.getServerName())
                    .append(":")
                    .append(request.getServerPort())
                    .append(request.getContextPath())
                    .append("/static/upload/welcomeMsg/")
                    .append(fileName);
                    
                    dto.setSelectedImgUrl(sb.toString());
                }
            }
        }
        
        
        for(String group : item.getGroupReceivers()){
            String userName = InMemoryStorage.findGroupUserName(group);
            if(userName != null){
                dto.getWxGroupSelected().add(SimpleCipher.encrypt(userName));
            }
        }
        
        dto.setThreshold(String.valueOf(item.getThreshold()));
        
        dto.setWxGroupAll(LogicProcess.getGroupList(false));

        return dto;
    }    
    
    //------------------ScheduledTask-----------------
    
    @RequestMapping(value="scheduledTask", method=RequestMethod.POST)
    @ResponseBody
    public Object scheduledTask(ScheduledTaskDto msg, HttpServletRequest request) {

        logger.debug("Enter /robot/scheduledTask");
        logger.debug("ScheduledTaskDto: {}", msg.toString());

        OperationResult result = new OperationResult(true, "ok");

        StringBuilder errorReport = new StringBuilder();
        String[] friends = null;
        boolean isCreate = false;
        String jobName = StringUtils.trim(msg.getKeyword());

        if(ScheduledTaskDto.CREATE_MODE.equals(msg.getMode())){

            isCreate = true;

            //Check keyword
            if(StringUtils.isBlank(jobName)){
                errorReport.append("定时任务名称为空\r\n");
            }else if(InMemoryStorage.scheduledTaskEntity.getMap().containsKey(jobName)){
                errorReport.append("定时任务名称[" + jobName + "]已存在\r\n");
            } 
        }                    

        //Check cron
        if(StringUtils.isBlank(StringUtils.trim(msg.getScheduledTime()))) {
            errorReport.append("运行时间为空\r\n");
        }else{
            try {
                CronExpression exp = new CronExpression(StringUtils.trim(msg.getScheduledTime()));
                Date d = new Date();
                d = exp.getNextValidTimeAfter(d); 
            } catch (ParseException e1) {
                errorReport.append("运行时间Cron格式错误\r\n");
            }   
        }

        //Check group and friend
        boolean noGroupTarget = false;
        boolean groupSelected = false;

        if( msg.getWxGroupSelected() == null ){                       
            if( msg.getCustomGroupSelected() == null ){
                noGroupTarget = true;
            }else{
                if(msg.getCustomGroupSelected().isEmpty()){
                    noGroupTarget = true;
                }
            }
        }else{

            if(msg.getWxGroupSelected().isEmpty()){
                if( msg.getCustomGroupSelected() == null ){
                    noGroupTarget = true;
                }else{
                    if(msg.getCustomGroupSelected().isEmpty()){
                        noGroupTarget = true;
                    }
                }
            }else{
                groupSelected = true;
            }
        }

        if(noGroupTarget){
            if(StringUtils.isBlank(StringUtils.trim(msg.getFriendReceivers()))
                    || StringUtils.trimToEmpty(msg.getFriendReceivers()).equals(";") ){
                errorReport.append("微信群、分组以及好友列表都为空\r\n");          
            }
        }else{
            if(groupSelected){
                for(String item : msg.getWxGroupSelected()){
                    String group = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(item));
                    if(!InMemoryStorage.userGroupCtrlEntity.getGroupList().contains(StringUtils.trim(group))){
                        errorReport.append("微信群[" + group + "]尚未被收编群\r\n");
                    }
                }                
            }
        }        


        //Check friend
        if(StringUtils.isNotBlank(StringUtils.trim(msg.getFriendReceivers()))){
            friends = StringUtils.trim(msg.getFriendReceivers()).split(";");
            for(String friend : friends){                   
                if(!InMemoryStorage.friendMap.keySet().contains(StringUtils.trim(friend))){
                    errorReport.append("[" + friend + "]不在好友列表中\r\n");
                }
            }                       
        }

        //Check msg
        if(StringUtils.trim(msg.getJobClassName()).equals("CommonJob")){
            if(StringUtils.isBlank(StringUtils.trim(msg.getTextToSend1())) 
                    && StringUtils.isBlank(StringUtils.trim(msg.getTextToSend2()))
                    && StringUtils.isBlank(StringUtils.trim(msg.getImgToSend())) ){
                errorReport.append("发送消息和图片都为空\r\n");                       
            }
        }                   

        //Check JobClass
        String className = StringUtils.trim(msg.getJobClassName());
        try{
            Class<?> jobClass = Class.forName( Constant.quartzPackagePath + "." + className);

            if(!Job.class.isAssignableFrom(jobClass)){
                errorReport.append("Class [" + className + "]不是Quartz的子类\r\n");
            }

        }catch(ClassNotFoundException e1){
            errorReport.append("Class [" + className + "]不存在\r\n");
        }

        if(errorReport.length() == 0){

            ScheduledTaskItem taskItem = new ScheduledTaskItem();

            taskItem.setTaskStatus(ScheduledTaskItem.READY);
            
            if(ScheduledTaskDto.EDIT_MODE.equals(msg.getMode())){
                
                ScheduledTaskItem old = InMemoryStorage.scheduledTaskEntity.getMap().get(jobName);
                
                if(old != null){
                    taskItem.setTaskStatus(old.getTaskStatus());
                }           
            }                                    
            
            ScheduledTaskCustomData customData = new ScheduledTaskCustomData();

            if( msg.getWxGroupSelected() != null ){
                if(!msg.getWxGroupSelected().isEmpty()){
                    for(String userName : msg.getWxGroupSelected()){
                        String group = InMemoryStorage.findGroupNickName(SimpleCipher.decrypt(userName));
                        if(StringUtils.isNotBlank(group)){
                            customData.getGroupReceivers().add(group);
                        }
                    }                     
                }
            }


            if(friends != null){
                for(String friend : friends){  
                    if(StringUtils.isNotBlank(friend)){
                        customData.getFriendReceivers().add(friend);
                    }
                }                           
            }

            //String[] friendReceivers = msg.getFriendReceivers().split(";");      
            //customData.setFriendReceivers(Arrays.asList(friendReceivers));

            customData.getTextList().add(msg.getTextToSend1());
            customData.getTextList().add(msg.getTextToSend2());    

            if(StringUtils.isNotBlank(msg.getImgToSend())){
                customData.getImageList().clear();
                customData.getImageList().add(request.getSession().getServletContext().getRealPath("") + "/static/upload/scheduledTask/" + msg.getImgToSend());
            }

            taskItem.setCustomData(customData);
                        
            taskItem.setScheduledTime(StringUtils.trim(msg.getScheduledTime()));
            taskItem.setJobClassName(Constant.quartzPackagePath + "." + StringUtils.trim(msg.getJobClassName()));

            if(LogicProcess.createOrModifyJob(jobName, taskItem, isCreate)){
                List<ScheduledTaskVo> list = LogicProcess.getScheduledTaskList();
                return list; 
            }else{
                result.setStatus(false);
                result.setDescription("保存失败");  
            }
        }else{    
            result.setStatus(false);
            result.setDescription("输入参数有误：" + errorReport);
        }

        return result;              
    }

    @RequestMapping("disScheduledTask")
    @ResponseBody
    public Object disScheduledTask(String name) {

        logger.debug("Enter /robot/disScheduledTask");
        logger.debug("name: {}", name);

        if(LogicProcess.pauseJob(name)){
            List<ScheduledTaskVo> list = LogicProcess.getScheduledTaskList();

            return list;
        }else{
            return new OperationResult(false, "fail");
        }
    }
    
    @RequestMapping("enScheduledTask")
    @ResponseBody
    public Object enScheduledTask(String name) {

        logger.debug("Enter /robot/enScheduledTask");
        logger.debug("name: {}", name);

        if(LogicProcess.resumeJob(name)){
            List<ScheduledTaskVo> list = LogicProcess.getScheduledTaskList();

            return list;
        }else{
            return new OperationResult(false, "fail");
        }
    }

    @RequestMapping("removeScheduledTask")
    @ResponseBody
    public Object removeScheduledTask(String name) {

        logger.debug("Enter /robot/removeScheduledTask/");
        logger.debug("name: {}", name);

        if(LogicProcess.removeJob(name)){
            List<ScheduledTaskVo> list = LogicProcess.getScheduledTaskList();

            return list;
        }else{
            return new OperationResult(false, "fail");
        }
    }
    
    @RequestMapping("getScheduledTask")
    @ResponseBody
    public Object getScheduledTask(String name, HttpServletRequest request) {

        logger.debug("Enter /robot/getScheduledTask");
        logger.debug("name: {}", name);

        ScheduledTaskItem item =
                InMemoryStorage.scheduledTaskEntity.getMap().get(name);
        
        ScheduledTaskDto dto = new ScheduledTaskDto();
        
        dto.setKeyword(name);
        
        dto.setScheduledTime(item.getScheduledTime());
        
        List<String> textList = item.getCustomData().getTextList();
        if(textList != null){
            if(textList.size() == 1){
                dto.setTextToSend1(textList.get(0));
            }else if(textList.size() >= 2){
                dto.setTextToSend1(textList.get(0));
                dto.setTextToSend2(textList.get(1));
            }          
        }
        
        List<String> imageList = item.getCustomData().getImageList();
        if(imageList != null){
            if(imageList.size() > 0){
                String image = imageList.get(0);
                
                if(StringUtils.isNotBlank(image)){
                    
                    String fileName = image.substring(image.lastIndexOf("/") + 1);
                    
                    dto.setImgToSend(fileName);                    

                    StringBuilder sb = new StringBuilder();
                    
                    sb.append(request.getScheme())
                    .append("://")
                    .append(request.getServerName())
                    .append(":")
                    .append(request.getServerPort())
                    .append(request.getContextPath())
                    .append("/static/upload/scheduledTask/")
                    .append(fileName);
                    
                    dto.setSelectedImgUrl(sb.toString());
                }
            }
        }        
        
        for(String group : item.getCustomData().getGroupReceivers()){
            String userName = InMemoryStorage.findGroupUserName(group);
            if(userName != null){
                dto.getWxGroupSelected().add(SimpleCipher.encrypt(userName));
            }
        }
        
        StringBuilder sb = new StringBuilder();
        for(String friend : item.getCustomData().getFriendReceivers()){
            sb.append(friend).append(";");
        }                           
        dto.setFriendReceivers(sb.toString());
        
        
        dto.setJobClassName( StringUtils.substring(item.getJobClassName(), 
                StringUtils.lastIndexOf(item.getJobClassName(), ".") + 1) );

              
        dto.setWxGroupAll(LogicProcess.getGroupList(false));

        return dto;
    }    

    @RequestMapping(value="testCron")
    @ResponseBody
    public Object testCron(String cron){

        String result = null;

        try {
            result =  GetExecuteTimeForCronExpression.convert(cron);
        } catch (ParseException e) {
            result = "Cron表达式解析异常";
        }
        
        return result;
    }
    
    //------------------FriendAutoReply-----------------
    @RequestMapping("friendAutoReply/{action}")
    @ResponseBody
    public Object disFriendAutoReply(@PathVariable String action) {

        Boolean status;
        
        if(StringUtils.isNotBlank(action)){
            
            if("enable".equals(action)){
                InMemoryStorage.allowFriendAutoReply = true;
            }else if("disable".equals(action)){
                InMemoryStorage.allowFriendAutoReply = false;
            }
            
        }

        status = InMemoryStorage.allowFriendAutoReply;
        return status;
    }

}
